#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    createActions();
    createMenus();
    restore();
    createTabs();
    createToolBars();
    createStatusBar();
    setCurrentFile("");

    projectCreator = 0;
    classifier = new Classifier;
}

MainWindow::~MainWindow()
{
    delete ui;
    if(projectCreator) delete projectCreator;
    if(classifier) delete classifier;

    classifier = 0;
    projectCreator = 0;
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    try
    {
        event->accept();
    }
    catch(exception &e)
    {
        qDebug() << e.what();
    }
}

/*
 *	Create numerous menu item and event listner
 *
 */
void MainWindow::createActions()
{
    openAction = new QAction(tr("&New Project"), this);
    openAction->setShortcut(tr("Ctrl+N"));
    openAction->setIcon(QIcon("./icons/new.png"));
    openAction->setStatusTip(tr("Create project file, please select an image file!"));
    connect(openAction, SIGNAL(triggered()), this, SLOT(createProj()));

    openProjAction = new QAction(tr("&Open Project"), this);
    openProjAction->setShortcut(tr("Ctrl+O"));
    openProjAction->setIcon(QIcon("./icons/open.png"));
    openProjAction->setStatusTip(tr("Open a project file"));
    connect(openProjAction, SIGNAL(triggered()), this, SLOT(openProj()));

    saveAction = new QAction(tr("&Save"), this);
    saveAction->setShortcut(tr("Ctrl+S"));
    saveAction->setIcon(QIcon("./icons/save.png"));
    saveAction->setStatusTip(tr("Save an image file"));
    connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));

    closeAction = new QAction(tr("Close Project"), this);
    connect(closeAction, SIGNAL(triggered()), this, SLOT(closeProj()));

    printAction = new QAction(tr("&Print"), this);
    printAction->setShortcut(tr("Ctrl+P"));
    connect(printAction, SIGNAL(triggered()), this, SLOT(print()));

    exitAction = new QAction(tr("&Exit"), this);
    exitAction->setShortcut(tr("Ctrl+E"));
    connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));

    countAction = new QAction(tr("&Count Seeds"), this);
    countAction->setShortcut(tr("Ctrl+Alt+C"));
    connect(countAction, SIGNAL(triggered()), this, SLOT(count()));

    detectAction = new QAction(tr("&Detect Germination"), this);
    detectAction->setShortcut(tr("Ctrl+Alt+D"));
    connect(detectAction, SIGNAL(triggered()), this, SLOT(detect()));

    analyzeAction = new QAction(tr("&Analyze Seeds"), this);
    analyzeAction->setShortcut(tr("Ctrl+Alt+A"));
    connect(analyzeAction, SIGNAL(triggered()), this, SLOT(analyze()));

    aboutAction = new QAction(tr("&About this application"), this);
    connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));

    histAction = new QAction(tr("Histogram"), this);
    connect(histAction, SIGNAL(triggered()), this, SLOT(histgram()));

    pcaAction = new QAction(tr("PCA"), this);
    pcaAction->setShortcut(tr("Ctrl+Alt+P"));
    pcaAction->setStatusTip(tr("Principle Component Analysis"));
    connect(pcaAction, SIGNAL(triggered()), this, SLOT(doPCA()));

    svmAction = new QAction(tr("SVM Training"), this);
    svmAction->setShortcut(tr("Ctrl+Alt+S"));
    svmAction->setStatusTip(tr("Support Vector Machine"));
    connect(svmAction, SIGNAL(triggered()), this, SLOT(trainSVM()));

    loadSvmAction = new QAction(tr("Load SVM File"), this);
    loadSvmAction->setStatusTip(tr("Load SVM file"));
    connect(loadSvmAction, SIGNAL(triggered()), this, SLOT(loadSVM()));

    mlpAction = new QAction(tr("MLP Training"), this);
    mlpAction->setShortcut(tr("Ctrl+Alt+M"));
    mlpAction->setStatusTip(tr("Multi Layer Perceptron"));
    connect(mlpAction, SIGNAL(triggered()), this, SLOT(trainMLP()));

    loadMlpAction = new QAction(tr("Load MLP File"), this);
    loadMlpAction->setStatusTip(tr("Load MLP file"));
    connect(loadMlpAction, SIGNAL(triggered()), this, SLOT(loadMLP()));

    boostAction = new QAction(tr("Boost Training"), this);
    boostAction->setShortcut(tr("Ctrl+Alt+B"));
    boostAction->setStatusTip(tr("Boost Decision Tree"));
    connect(boostAction, SIGNAL(triggered()), this, SLOT(trainBoost()));

    loadBoostAction = new QAction(tr("Load Boost File"), this);
    loadBoostAction->setStatusTip(tr("Load Boost file"));
    connect(loadBoostAction, SIGNAL(triggered()), this, SLOT(loadBoost()));
}

/*
 *	Create numerous menu item and append to the main ui
 */
void MainWindow::createMenus()
{
    // File menu
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(openAction);
    fileMenu->addAction(openProjAction);
    fileMenu->addAction(saveAction);
    fileMenu->addAction(closeAction);
    fileMenu->addAction(printAction);
    fileMenu->addAction(exitAction);

    // Edit menu
    editMenu = menuBar()->addMenu(tr("&Edit"));

    // View menu
    viewMenu = menuBar()->addMenu(tr("&View"));
    viewMenu->addAction(histAction);

    // Tools menu
    toolsMenu = menuBar()->addMenu(tr("&Tools"));
    toolsMenu->addAction(pcaAction);
    // Svm submenu
    svmSubMenu = toolsMenu->addMenu(tr("&SVM"));
    svmSubMenu->addAction(svmAction);
    svmSubMenu->addAction(loadSvmAction);
    // Mlp submenu
    mlpSubMenu = toolsMenu->addMenu(tr("&MLP"));
    mlpSubMenu->addAction(mlpAction);
    mlpSubMenu->addAction(loadMlpAction);
    // Boost submenu
    boostSubMenu = toolsMenu->addMenu(tr("&Boost"));
    boostSubMenu->addAction(boostAction);
    boostSubMenu->addAction(loadBoostAction);

    // Window menu
    windowMenu = menuBar()->addMenu(tr("&Window"));
    windowMenu->addAction(analyzeAction);
    windowMenu->addAction(countAction);
    windowMenu->addAction(detectAction);

    // Options menu
    optionsMenu = menuBar()->addMenu(tr("&Options"));

    // Help menu
    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAction);
}

/*
 *	Main tool bar contains short cut menu item
 */
void MainWindow::createToolBars()
{
    newProj = new QToolButton(this);
    newProj->setText(tr(""));
    newProj->setIcon(QIcon("icons/new.png"));
    newProj->setToolTip("Create new project");
    ui->mainToolBar->addWidget(newProj);
    connect(newProj, SIGNAL(clicked()), this, SLOT(createProj()));

    open = new QToolButton(this);
    open->setText(tr(""));
    open->setIcon(QIcon("icons/open.png"));
    open->setToolTip("Open project");
    ui->mainToolBar->addWidget(open);
    connect(open, SIGNAL(clicked()), this, SLOT(openProj()));
}

/*
 *	Create main tabs within ui including image acquistion, experiment data
 *	seed count, shape analysis, germination analysis and image process
 */
void MainWindow::createTabs()
{
    countingTab = new CountingTab;
    detectionTab = new DetectionTab;
    analysisTab = new AnalysisTab;
    germTab = new GermTab;
    imgProcTab = new ImgProcTab;
    imgAcqTab = new ImgAcquisitionTab;

    ui->tabWidget->addTab(imgAcqTab, tr("Image Acquisition"));
    ui->tabWidget->addTab(detectionTab, tr("Experiment Data"));
    ui->tabWidget->addTab(countingTab, tr("Seed Count"));
    ui->tabWidget->addTab(analysisTab, tr("Shape Analysis"));
    ui->tabWidget->addTab(germTab, tr("Germination Analysis"));
    ui->tabWidget->addTab(imgProcTab, tr("Image Process"));

    connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(showTab(int)));
}

/*
 *	Creat status bar for message
 */
void MainWindow::createStatusBar()
{
    fileNameLabel = new QLabel(tr(""), statusBar());
    fileNameLabel->setAlignment(Qt::AlignHCenter);
    fileNameLabel->setMinimumSize(fileNameLabel->sizeHint());
    statusBar()->addWidget(fileNameLabel);
}

void MainWindow::updateStatusBar(const QString& curFile)
{
    fileNameLabel->setText(curFile);
}

void MainWindow::setCurrentFile(const QString &fileName)
{
    curFile = fileName;
}

/*
 *	Based on selected image file, create a project file
 */
void MainWindow::createProj()
{    
	// check if another project has opened, if so, close it 
	// before create a new one
    if(detectionTab->isProjOpened())
    {
        closeProj();
    }

    informationControl = new InformationControl;
    connect(informationControl, SIGNAL(finished(int)), this, SLOT(inputDone(int)));
    informationControl->show();
}

/*
 *	When a project related information has been entered, then project creator will 
 *	creat a new project with entered informtion and save to database. Then open
 *	the just created project
 *	
 */
void MainWindow::inputDone(int result)
{
    if(result == 1 && informationControl)
    {
        if(projectCreator == 0)
            projectCreator = new ProjectCreator(informationControl->getFile(),
                                            informationControl->getDir(),
                                            informationControl->getStartDateTime(),
                                            informationControl->getInterval(),
                                            informationControl->isIncluded());
		// open just created project file
        pop(projectCreator->getExpFile());

    }
    else
    {
        ui->statusBar->showMessage("A project has not been created!!!  ", 3000);
    }
}

/*
 *	Show tab when particular tab has been clicked
 */
void MainWindow::showTab(int tab)
{
    if(tab == 0)
        imgAcqTab->showContent();
    else if(tab == 1)
        detectionTab->showContent();
    else if(tab == 2)
        countingTab->showContent();
    else if(tab == 3)
        analysisTab->showContent();
    else if(tab == 4)
        germTab->showContent();
    else if(tab == 5)
        imgProcTab->showContent();
}

/* 
 *	Open a project when open-project is selected
 */
void MainWindow::openProj()
{
    if(detectionTab->isProjOpened())
    {
        int ans = QMessageBox::warning(this, tr("Open Project"),
                                       tr("A project file has been opened, do you still want to open "
                                          "a new project ?"), QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes);

        switch (ans){
            case QMessageBox::Cancel : return; break;
            case QMessageBox::Yes : close(); break;
            case QMessageBox::No : return; break;
            default : break;
        }
    }
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open Project file"), "./data",
                                                    tr("Project Files (*.sgf)"));
	
	// Populate ui with project related information
    pop(fileName);

}

/*
 *	When a project file is loaded, populate all
 *	tabs with image loader
 */
void MainWindow::pop(const QString& fileName)
{
    if(!fileName.isEmpty() && fileName.contains(".sgf"))
    {
        // DetectionTab is used to open project file
        // 'fileName' is the name of the project file
        detectionTab->populate(fileName);
        connect(detectionTab->getLoader(), SIGNAL(imageSelected(QString)), this, SLOT(updateStatusBar(QString)));
		// Add image loader to every other tab
        countingTab->addLoader(detectionTab->getLoader());
        analysisTab->addLoader(detectionTab->getLoader());
        germTab->addLoader(detectionTab->getLoader());
        imgProcTab->addLoader(detectionTab->getLoader());
        imgAcqTab->addLoader(detectionTab->getLoader());
		// Switch to experiment data tab
        ui->tabWidget->setCurrentIndex(1);
    }
    else
    {
        ui->statusBar->showMessage("Please select a project file  ", 3000);
    }
}

/*	
 *	Save result image that currently being displayed to user entered file name
 */
bool MainWindow::save()
{
    bool isSaved = false;
    QString imageName = QFileDialog::getSaveFileName(this, tr("Save result image file"), "/home",
                                                     tr("Image file (*.jpg *.png *.bmp"));
    
	// Save currently result image with entered file name and path
	// then return result 
	isSaved = detectionTab->saveImage(imageName);

    if(isSaved)
    {	
		// Update status bar with saved file name and path
        saveFile(imageName);
    }
    else return false;

    return true;
}

/*
 *	Close currently opened project, recreate each tab
 */
bool MainWindow::closeProj()
{
    restore();
    createTabs();
    return true;
}

/*
 *	updated status bar for saved image file name and path
 */
bool MainWindow::saveFile(const QString &fileName)
{
    // Write File
    setCurrentFile(fileName);
	// Update status bar
    statusBar()->showMessage(tr("File saved"), 3000);
    return true;
}

/*
 *	Draw 2-D histogram for currently opened image
 */
void MainWindow::histgram()
{
    detectionTab->drawHistogram();
}

/*
 *	Perform Principle Component Analysis
 */
void MainWindow::doPCA()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open file for Principle Component Analysis"), "./output",
                                                    tr("PCA file (*.csv)"));

    if(fileName.length() > 0)
    {
        classifier->pcaCompress(fileName);
    }
}

/*
 *  Perform Support Vector Machine
 */
void MainWindow::trainSVM()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open training file for Support Vector Machines"), "./output",
                                                    tr("SVM training file (*.csv)"));

    if(fileName.length() > 0)
    {
        classifier->trainSVM(fileName);
        germTab->svmReady(classifier);
        ui->tabWidget->setCurrentIndex(4);
        statusBar()->showMessage(tr("SVM has been trained"));
    }
}

void MainWindow::loadSVM()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open trained SVM file"), "./output",
                                                    tr("SVM file (*.xml)"));
    // SVM Classifier has been loaded successfully
    if(classifier->loadSVM(fileName))
    {
        germTab->svmReady(classifier);
        ui->tabWidget->setCurrentIndex(4);
        statusBar()->showMessage(tr("SVM has been successfully loaded"));
    }
    else
        statusBar()->showMessage(tr("No SVM is available"));
}

/*
 * Multi Layer Perceptron
 */
void MainWindow::trainMLP()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open training file for Multi Layer Perceptrons"), "./output",
                                                    tr("MLP training file (*.csv)"));

    if(fileName.length() > 0)
    {
        classifier->trainMLP(fileName);
        germTab->mlpReady(classifier);
        ui->tabWidget->setCurrentIndex(4);
        statusBar()->showMessage(tr("MLP has been trained"), 3000);
    }
}

void MainWindow::loadMLP()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open trained MLP file"), "./output",
                                                    tr("MLP file (*.xml)"));
    // MLP classifier has been loaded successfully
    if(classifier->loadMLP(fileName))
    {
        germTab->mlpReady(classifier);
        ui->tabWidget->setCurrentIndex(4);
        statusBar()->showMessage(tr("MLP has been successfully loaded"), 3000);
    }
    else
        statusBar()->showMessage(tr("No MLP is available"));
}

void MainWindow::trainBoost()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open training file for Boost Decision Tree"), "./output",
                                                    tr("Boost training file (*.csv)"));

    if(fileName.length() > 0)
    {
        classifier->trainBoost(fileName);
        germTab->boostReady(classifier);
        ui->tabWidget->setCurrentIndex(4);
        statusBar()->showMessage(tr("Boost has been trained"));
    }
}

void MainWindow::loadBoost()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open trained Boost file"), "./output",
                                                    tr("Boost file (*.xml)"));
    // Boost Classifier has been loaded successfully
    if(classifier->loadBoost(fileName))
    {
        germTab->boostReady(classifier);
        ui->tabWidget->setCurrentIndex(4);
        statusBar()->showMessage(tr("Boost has been successfully loaded"));
    }
    else
        statusBar()->showMessage(tr("No Boost is available"));

}

/*
 *  This method print the result image of the right side of the
 *  image loader in color format
 *
 */
void MainWindow::print()
{
    QPrinter printer;
    QPrintDialog pDialog(&printer, this);
    QPainter painter;

    Mat img = detectionTab->getLoader()->getResultImage();
    Mat rgb;

    if(img.data)
    {
        // Print color image
        cvtColor(img, rgb, CV_BGR2RGB);
        int w = rgb.cols;
        int h = rgb.rows;
        // Get QImage to rescale to 1/4 of original size
        QImage image = QImage(rgb.data, w, h, rgb.step, QImage::Format_RGB888);
        image = image.scaled(w, h, Qt::KeepAspectRatio, Qt::FastTransformation);

        // Open printer dialog
        if(pDialog.exec() == QDialog::Accepted)
        {
            if(!painter.begin(&printer))
            {
                qWarning("Fail to connect!");
                return;
            }
            painter.drawImage(10, 10, image);
            if(!printer.newPage())
            {
                qWarning("Fail to print!");
                return;
            }
            // Close printer and painter
            painter.end();
        }
    }
    else
    {
        qWarning("No result image available");
    }
}

void MainWindow::about()
{
    QMessageBox::about(this, tr("About Application"),
                 tr("This application explore image texture analysis methods "
                    "to create project file, open project file and count seeds, "
                    "also this application several algorithm to detect seed germination."));
}

void MainWindow::count()
{
    ui->tabWidget->setCurrentIndex(2);
}

void MainWindow::detect()
{
    ui->tabWidget->setCurrentIndex(4);
}

void MainWindow::analyze()
{
    ui->tabWidget->setCurrentIndex(3);
}

void MainWindow::restore()
{
    ui->tabWidget->clear();
}
